package com.pi;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.maven.cli.MavenCli;
import org.ho.yaml.Yaml;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.core.wc2.SvnLog;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;

/**
 * Hello world!
 */
public class App {

    private static Logger log = LoggerFactory.getLogger(App.class);

    //svn 连接重用
    private static Map<String, SVNClientManager> svnClientCache = new HashMap();

    private static final String LINE_SEPARATOR = System.getProperty("line.separator", "\n");

    public static void main(String[] args) throws Exception {

        //装载svn lib
        setupLibrary();

        //加载打包配置
        Config config = loadConfig();

        log.info(ToStringBuilder.reflectionToString(config, ToStringStyle.MULTI_LINE_STYLE));

        //获得输出目录
        String sourceStore = config.getSourceStoreDir();

        if (StringUtils.isEmpty(sourceStore)) {
            throw new Exception("输出目录不能为空");
        }

        RepertorySetting baseRepertory = config.getBaseRepertory();

        RepertorySetting newRepertory = config.getNewRepertory();

        log.info("导出基础版本");
        //下载基础版本
        File baseVersionFile = exportSvnVersion(config.getSourceStoreDir(), baseRepertory);

        log.info("导出对比基础版本");
        //下载对比版本
        File newVersionFile = exportSvnVersion(config.getSourceStoreDir(), newRepertory);

        log.info("导出完成,进行编译");

        String baseVersionPath = baseVersionFile.getAbsolutePath();
        String newVersionPath = newVersionFile.getAbsolutePath();

        //分别执行打包命令
        MavenCli cli = new MavenCli();

        long s = System.currentTimeMillis();
        cli.doMain(new String[]{"clean", "compile", "package"},
                baseVersionPath, System.out, System.out);

        log.info("编译完成: " + baseVersionPath + "  编译耗时:" + (System.currentTimeMillis() - s));

        s = System.currentTimeMillis();

        //"clean",
        log.info("编译新版本");
        cli.doMain(new String[]{"clean", "compile", "package"},
                newVersionPath, System.out, System.out);

        log.info("编译完成: " + newVersionPath + "  编译耗时:" + (System.currentTimeMillis() - s));

        //获得对比基目录配置
        String compareBasePath = config.getCompareBasePath();

        File newVersionDir;
        File baseVersionDir;

        if (StringUtils.isNotEmpty(compareBasePath)) {
            //转换变量
            baseVersionDir = new File(StringUtils.replace(compareBasePath, "${project}", baseVersionPath));
            newVersionDir = new File(StringUtils.replace(compareBasePath, "${project}", newVersionPath));
        } else {
            newVersionDir = newVersionFile;
            baseVersionDir = baseVersionFile;
        }
        log.info("进行文件对比.");

        //打包之后进行比对,获得变更的文件列表
        List<PatchFile> changeFiles = ComparePlugin.exec(newVersionDir, baseVersionDir);

        log.info("差异文件:" + changeFiles.toString());

        //生成补丁生成插件
        File patchDir = createPatchDir(config);

        log.info("输出差异文件");
        //执行打包插件
        PatchPlugin.exec(changeFiles, newVersionDir.getAbsolutePath(), patchDir.getAbsolutePath(), config.getPackZipDir());

        log.info("生成补丁完成:" + patchDir.getAbsolutePath());

        //执行打包操作
        if (config.isPackToZip()) {
            log.info("执行zip 操作:" + patchDir.getAbsolutePath());

            File file = new File(config.getPackZipDir());

            FileUtil.createFileIfNotExists(file);

            //生成压缩文件
            File zipFile = new File(file.getParentFile(), file.getName() + ".zip");

            ZipPlugin.zip(file, zipFile.getAbsolutePath());

            log.info("压缩完成:" + zipFile.getAbsolutePath());

            String devName = "谢兴兴";
            String testerName = "卢春健";

            String patcherName = zipFile.getName();

            String lastLog = getSvnLog(baseRepertory, newRepertory);

            log.info("更新日志:" + lastLog);

//            //if(StringUtils.isEmpty(lastLog)){
//                lastLog = "修复数据源问题";
//            //}

            DocPlugin.genTestCase(config, patcherName, lastLog, devName, testerName);
            DocPlugin.gen(config, patcherName, lastLog, devName, testerName);

            //复制文件到版本发布目录
            ///FileUtils.copyFileToDirectory(zipFile, new File("/Users/chen/Desktop/yame/pub_rep/YmTest/TS/server/"));
        }

    }

    /**
     * 获得日志信息
     *
     * @param baseRepertory
     * @param newRepertory
     * @return
     * @throws SVNException
     */
    public static String getSvnLog(RepertorySetting baseRepertory, RepertorySetting newRepertory) throws SVNException {

        SVNClientManager scm = authSvn(baseRepertory.getUrl(), baseRepertory.getUsername(), baseRepertory.getPwd());

        if (null != scm) {

            SVNLogClient client = scm.getLogClient();
            SVNRevision start = SVNRevision.parse(baseRepertory.getVersion());
            SVNRevision end = SVNRevision.parse(newRepertory.getVersion());

            final StringBuilder logBuffer = new StringBuilder(1024);
            client.doLog(SVNURL.parseURIDecoded(baseRepertory.getUrl()), new String[]{""}, end, start, end,
                    false, false, false, 20,
                    new String[]{}, getLogEntryHandler(logBuffer, start.getNumber()));

            return logBuffer.toString();
        }
        return "";

    }

    /** */
    private static ISVNLogEntryHandler getLogEntryHandler(final StringBuilder logBuffer, long ignoreVersion) {
        return new ISVNLogEntryHandler() {
            public void handleLogEntry(SVNLogEntry entry) throws SVNException {

                //忽略作为对比基础的版本日志
                if (ignoreVersion != entry.getRevision()) {
                    logBuffer.append(entry.getMessage()).append(LINE_SEPARATOR);
                }
            }
        };
    }

    /**
     * 创建补丁目录
     *
     * @param config
     * @return
     */
    private static File createPatchDir(Config config) throws Exception {

        String packDir = config.getPackDir();

        String packZipDir = config.getPackZipDir();

        String docOutput = config.getDocOutput();

        if (StringUtils.isNotEmpty(packDir)) {

            String today = DateFormatUtils.format(new Date(), "yyyyMMdd");

            //替换变量
            packDir = StringUtils.replace(packDir, "${date}", today);
            packDir = StringUtils.replace(packDir, "${sourceStoreDir}", config.getSourceStoreDir());

            //压缩目录替换变量
            packZipDir = StringUtils.replace(packZipDir, "${date}", today);
            packZipDir = StringUtils.replace(packZipDir, "${sourceStoreDir}", config.getSourceStoreDir());

            int patcherNum = 0;
            String temp;

            do {
                patcherNum++;
                temp = StringUtils.replace(packDir, "${patcherNum}", String.valueOf(patcherNum));
            } while (new File(temp).exists());

            packDir = temp;
            packZipDir = StringUtils.replace(packZipDir, "${patcherNum}", String.valueOf(patcherNum));
            docOutput = StringUtils.replace(docOutput, "${sourceStoreDir}", config.getSourceStoreDir());

            //创建打包生成目录
            File file = new File(packDir);
            FileUtil.createFileIfNotExists(file);

            config.setPackDir(packDir);
            config.setPackZipDir(packZipDir);

            config.setDocOutput(docOutput);

            return file;

        } else {
            throw new Exception("打包目录不能为空");
        }

    }

    /**
     * 导出svn版本
     *
     * @param sourceStore
     * @param repertory
     * @return
     * @throws Exception
     */
    private static File exportSvnVersion(String sourceStore, RepertorySetting repertory) throws Exception {

        String version = repertory.getVersion();

        //创建代码存储目录
        File sourceDir = new File(sourceStore, "-1".equals(version) ? "newest" : "r" + version);
        FileUtil.createFileIfNotExists(sourceDir);

        //连接SVN服务器
        SVNClientManager svnClientManager = authSvn(repertory.getUrl(),
                repertory.getUsername(), repertory.getPwd());

        //添加事件监听
        SVNUpdateClient updateClient = svnClientManager.getUpdateClient();
        updateClient.setEventHandler(new UpdateEventHandler());

        //checkout 地址
        SVNURL svnurl = SVNURL.parseURIEncoded(repertory.getUrl());

        //获得下载的版本号
        SVNRevision svnRevision = SVNRevision.create(Long.parseLong(version));

        //进行checkout 操作
        long checkout = checkout(svnClientManager, svnurl, svnRevision, sourceDir, SVNDepth.INFINITY);

        log.info("输出文件:" + checkout);

        return sourceDir;
    }

    /**
     * 验证登录svn
     */
    public static SVNClientManager authSvn(String svnRoot, String username,
                                           String password) {

        SVNClientManager svnClientManager = null;

        if (StringUtils.isNotEmpty(svnRoot)) {

            svnClientManager = svnClientCache.get(svnClientCache);

            if (null == svnClientManager) {

                // 身份验证
                ISVNAuthenticationManager authManager = SVNWCUtil
                        .createDefaultAuthenticationManager(username, password.toCharArray());
                SVNRepository repository = null;
                try {
                    repository = SVNRepositoryFactory.create(SVNURL
                            .parseURIEncoded(svnRoot));
                } catch (SVNException e) {
                    log.error(e.toString());
                    return null;
                }
                // 创建身份验证管理器
                repository.setAuthenticationManager(authManager);

                DefaultSVNOptions options = SVNWCUtil.createDefaultOptions(true);

                // 创建库连接
                svnClientManager = SVNClientManager.newInstance(options,
                        authManager);

                svnClientCache.put(svnRoot, svnClientManager);
            }
        }
        return svnClientManager;
    }

    /**
     * 通过不同的协议初始化版本库
     */
    public static void setupLibrary() {
        DAVRepositoryFactory.setup();
        SVNRepositoryFactoryImpl.setup();
        FSRepositoryFactory.setup();
    }

    /**
     * recursively checks out a working copy from url into wcDir
     *
     * @param clientManager
     * @param url           a repository location from where a Working Copy will be checked out
     * @param revision      the desired revision of the Working Copy to be checked out
     * @param destPath      the local path where the Working Copy will be placed
     * @param depth         checkout的深度，目录、子目录、文件
     * @return
     * @throws SVNException
     */
    public static long checkout(SVNClientManager clientManager, SVNURL url,
                                SVNRevision revision, File destPath, SVNDepth depth) {

        SVNUpdateClient updateClient = clientManager.getUpdateClient();


        /*
         * sets externals not to be ignored during the checkout
         */
        updateClient.setIgnoreExternals(false);
        /*
         * returns the number of the revision at which the working copy is
         */
        try {
            return updateClient.doCheckout(url, destPath, revision, revision, depth, false);
        } catch (SVNException e) {
            log.error(e.toString());
        }
        return 0;
    }

    /**
     * 加载配置
     *
     * @return
     */
    private static Config loadConfig() throws Exception {

        try {
            Config config = Yaml.loadType(App.class.getClassLoader()
                    .getResourceAsStream("app.yml"), Config.class);

            //读取配置之后, 进行校验

            RepertorySetting baseRepertory = config.getBaseRepertory();
            RepertorySetting newRepertory = config.getNewRepertory();

            //如果新版本没有填写账号密码,则使用老版本的账号与密码
            if (StringUtils.isEmpty(newRepertory.getUsername())) {
                newRepertory.setUsername(baseRepertory.getUsername());
            }

            if (StringUtils.isEmpty(newRepertory.getPwd())) {
                newRepertory.setPwd(baseRepertory.getPwd());
            }

            //如果新版本地址为空, 则使用老的版本
            if (StringUtils.isEmpty(newRepertory.getUrl())) {
                newRepertory.setUrl(baseRepertory.getUrl());
            }

            if (baseRepertory.getUrl().equals(baseRepertory.getUrl()) &&
                    baseRepertory.getVersion().equals(newRepertory.getVersion())) {
                //如果地址一致情况, 并且版本号一致,则抛出异常
                throw new Exception("基础版本和新增版本一致,取消任务");
            }

            return config;

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;

    }

    public static class UpdateEventHandler implements ISVNEventHandler {

        @Override
        public void handleEvent(SVNEvent svnEvent, double v) throws SVNException {

            System.out.println(svnEvent.getFile().getAbsolutePath());
        }

        @Override
        public void checkCancelled() throws SVNCancelException {

        }
    }

}
